//===--- LLVMTypePHPRCIdentity.cpp - LLVM RCIdentity Analysis for Swift -----===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//

#include "polarphp/llvmpasses/Passes.h"
#include "polarphp/llvmpasses/internal/LLVMARCOpts.h"
#include "llvm/IR/Module.h"

using namespace llvm;
using polar::TypePHPRCIdentity;

// Register this pass...
char TypePHPRCIdentity::ID = 0;
INITIALIZE_PASS(TypePHPRCIdentity, "typephp-rc-identity",
"polarphp RC Identity Analysis", false, true)

bool TypePHPRCIdentity::doInitialization(Module &M) {
   return true;
}

llvm::Value *
TypePHPRCIdentity::stripPointerCasts(llvm::Value *Val) {
   return Val->stripPointerCasts();
}

llvm::Value *
TypePHPRCIdentity::stripReferenceForwarding(llvm::Value *Val) {
   auto Inst = dyn_cast<Instruction>(Val);
   if (!Inst)
      return Val;
   auto Kind = classifyInstruction(*Inst);
   switch(Kind) {
      case RT_RetainN:
      case RT_UnknownObjectRetainN:
      case RT_BridgeRetainN:
      case RT_ReleaseN:
      case RT_UnknownObjectReleaseN:
      case RT_BridgeReleaseN:
      case RT_FixLifetime:
      case RT_Retain:
      case RT_UnknownObjectRetain:
      case RT_Release:
      case RT_UnknownObjectRelease:
      case RT_Unknown:
      case RT_AllocObject:
      case RT_NoMemoryAccessed:
      case RT_BridgeRelease:
      case RT_BridgeRetain:
      case RT_RetainUnowned:
      case RT_CheckUnowned:
//      case RT_ObjCRelease:
      case RT_EndBorrow:
         break;
         // ObjC forwards references.
//      case RT_ObjCRetain:
//         Val = cast<CallInst>(Inst)->getArgOperand(0);
//         break;
   }
   return Val;
}

llvm::Value *
TypePHPRCIdentity::getTypePHPRCIdentityRoot(llvm::Value *Val) {
   // Only allow this method to go up a fixed number of levels to make sure
   // we don't explode compile time.
   llvm::Value *OldVal = Val;
   unsigned levels = 0;
   do {
      llvm::Value *NewVal = Val;
      // Try to strip off pointer casts and reference forwarding.
      Val = stripPointerCasts(Val);
      Val = stripReferenceForwarding(Val);
      // Nothing was stripped off.
      if (NewVal == Val)
         break;
      // Hit max number of levels.
      if (++levels > MaxRecursionDepth)
         return OldVal;
   } while (true);
   return Val;
}

llvm::ImmutablePass *polar::createTypePHPRCIdentityPass() {
   initializeTypePHPRCIdentityPass(*PassRegistry::getPassRegistry());
   return new TypePHPRCIdentity();
}
